package com.bear.sgg.springboot_11_cache.service;

import com.bear.sgg.springboot_11_cache.entity.Employee;
import com.bear.sgg.springboot_11_cache.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

/**
 * @ClassNmae EmployeeService
 * @Description TODO
 * @Author bear
 * @Date 2020/3/17 0017 上午 9:37
 */
//CacheConfig注解可以抽取缓存的公共配置
@CacheConfig(cacheNames = "emp")
@Service
public class EmployeeService {

    @Autowired
    EmployeeMapper employeeMapper;

    /**
     * 通过@Cacheable注解可以将方法的结果进行缓存，以后需要使用到相同数据时，可从缓存中直接获取，而不用调用该方法
     * 其执行流程为：1.先查询缓存。2.缓存中没数据再执行方法然后放入缓存。
     * 一个CacheManager中管理了几个Cache组件，对缓存的CRUD操作在cache组件中
     * 注解的几个属性
     *  cacheName/value：指定缓存组件的名字（数组，可以将数据放到多个缓存组件中）
     *  key：数据是通过key-value的形式进行存储的，这里的key指的是需要缓存的数据的键值，默认使用第一个方法参数的值，
     *       也可以编写spEL来赋值：如#id（参数id的值）、#root.args[0](第一个参数的值)、#a0、#p0
     *  keyGenerator：指定键值生成器。（key、keyGenerator二选一）
     *  cacheManager：指定缓存管理器，或者cacheResolver指定获取解析器
     *  condition：指定缓存条件（如"#id>0"）
     *  unless：指定不缓存条件(如"#result == null"（结果为空则不缓存）)
     *
     * @param id
     * @return
     */
    @Cacheable(
            cacheNames = {"emp"},
            keyGenerator = "myKeyGenerator")
    public Employee selectEmpById(Integer id) {
        return employeeMapper.selectEmpById(id);
    }

    /**
     * 通过@CachePut注解，可以在更新数据的同时同步更新缓存
     * 其执行流程为：1.先执行方法。2.再将方法结果放入缓存
     * 如果要同步更新上述@Cacheable注解方法所缓存的数据，需要注意两点：
     *  1.数据应该在同一个cache组件中（即cacheName一致）
     *  2.数据的key应该一致
     * @param employee
     * @return
     */
    @CachePut(
            cacheNames = "emp",
            keyGenerator = "myKeyGenerator2"
    )
    public Employee updateEmp(Employee employee) {
        employeeMapper.updateEmp(employee);
        return employee;
    }

    /**
     * 通过@CacheEvict注解，可以删除缓存中的数据
     * 几个属性：
     *  allEntries：是否删除特定缓存组件中的缓存（值为true则不管key是什么，emp中所有的数据会被清空）
     *  beforeInvocation：是否在方法之前执行（默认是false）
     *
     * @param id
     * @return
     */
    @CacheEvict(
            cacheNames = {"emp"},
            key = "'[' + #id + ']'")
    public int deleteEmpById(Integer id) {
        //return employeeMapper.deleteEmpById(id);
        return 1;
    }

    /**
     * 通过@Caching属性可以配置更为复杂的缓存规则
     *
     * @param lastName
     * @return
     */
    @Caching(
            cacheable = {
                    @Cacheable(key = "#lastName")
            },
            put = {
                    @CachePut(key = "'[' + #result.id + ']'"),  //将结果的id作为键值
                    @CachePut(key = "#result.email")    //将结果的email值作为键值
            }
    )
    public Employee selectEmpByLastName(String lastName) {
        return employeeMapper.selectEmpByLastName(lastName);
    }

    public int insertEmp(Employee employee) {
        return employeeMapper.insertEmp(employee);
    }
}
